#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <string.h>
#include <ifaddrs.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/kernel.h>
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/stat.h>

#include "udpSocketLib.h"
#include "udp_struct.h"
#include "srio.h"

#define UDP_RECV_DATA_PORT  8000
#define UDP_SEND_DATA_PORT  8501

#define UDP_SEND_IP   "192.168.100.6"
#define UDP_BROAD_IP   "192.168.100.255"

#define UDP_RECV_GROUP "224.0.0.10"
#define UDP_SEND_GROUP "230.2.15.1"

#define SPI_HEAD 0x5A5A
#define SPI_TAIL 0xA5A5

int iSockFd_recv = -1;
int iSockFd_send = -1;

struct sockaddr_in st_addrSend_send;

unsigned int g_ipAddr[4];

extern unsigned char send_buf[16384];

unsigned char spi_send_buf[16384]={0};
extern int spi_send_data(char *buf,int length);


void NetInit(unsigned int chasisNum,unsigned int slotNum)
{
	char _buf[100];
	char cmdline[200];

	g_ipAddr[0]=192;
	g_ipAddr[1]=168;
	g_ipAddr[2]=100;
	g_ipAddr[3]=100+(slotNum-1)*16;

	sprintf (_buf, "%d.%d.%d.%d",g_ipAddr[0],g_ipAddr[1],g_ipAddr[2],g_ipAddr[3]);
	printf("IP:%s\n",_buf);

	sprintf(cmdline,"ifconfig eth0 %s",_buf);
	system(cmdline);
}

static void OnSocket(void * pParent,int nID,char * buf,int len)
{
	char * addr;
	int  port;
	int i;
	unsigned int reset;
	unsigned int head,tail;
	unsigned int _data;
	unsigned short workmode;
	int *tx_data;
	int fdTx;
	SDIStruct *sdidata;

	addr = udpGetRecvAddress(nID);
	port = udpGetRecvPort(nID);

	printf("recv from: addr is %s port = %d, len = %d\t",addr,port,len);
	if(len < 0)
	{
		return;
	}
	else
	{
		sdidata=(SDIStruct *)buf;
		head=sdidata->head;
		tail=sdidata->tail;
		printf("head is 0x%x tail is 0x%x\n",head,tail);
		if(head!=SDI_HEAD||tail!=SDI_TAIL)
		{
			printf("wrong head or tail, drop data.\n");
			return;
		}
		reset=sdidata->sysreset;
		if(reset==1)
		{
			printf("system reset\n");
		}
		workmode=sdidata->ctrl1.workMode;
		if(workmode==1)
		{
			printf("debug mode,send data back\n");
			memcpy((void*)send_buf,(void*)buf,sizeof(SDIStruct));
			udp_send_data(sizeof(SDIStruct));
			return;
		}
		else
		{
			printf("using srio send data to v7\n");
//			memcpy(spi_send_buf,SPI_HEAD,2);
//			memcpy(spi_send_buf+2,sizeof(SDIStruct),2);
//			memcpy((void*)(spi_send_buf+4),(void*)buf,sizeof(SDIStruct));
//			memcpy(spi_send_buf+4+sizeof(SDIStruct),SPI_TAIL,2);
//			spi_send_data((unsigned char*)buf,1280);


			printf("read srio link status\n");
			_data=GetGpioReg(XPAR_SRIO_AXI_CONFIG_0_S00_AXI_BASEADDR,SRIO_LNK_REG_1);
			printf("SRIO_LNK_REG_1 = 0x%x\n",_data);

			fdTx = open ("/dev/mem", O_RDWR | O_SYNC);
			if (fdTx < 0)
			{
				printf("cannot open /dev/mem.");
				return;
			}
			tx_data = (int *)mmap(NULL, 0x800, PROT_READ | PROT_WRITE, MAP_SHARED, fdTx, 0x2300000);
			if (tx_data < 0)
			{
				printf("mmap failed.");
				return;
			}
			memcpy((void*)tx_data,(void*)buf,1280);
			srio_send(0x2300000, 0x20000000, 1280, 0xdd, 0x54);
			srio_send_doorbell(0xdd,0x1234);
			printf("srio send data ok\n");
			munmap(tx_data, 0x800);
			close(fdTx);
			return;
		}
	}
}
void udp_create_socket_recv()
{
	char buffer[100];
	sprintf (buffer, "%d.%d.%d.%d",g_ipAddr[0],g_ipAddr[1],g_ipAddr[2],g_ipAddr[3]);
	printf("IP:%s\n",buffer);
	iSockFd_recv=udpCreateSocket(buffer,UDP_RECV_GROUP,UDP_RECV_DATA_PORT);
	if(iSockFd_recv < 0)
	{
		printf("udp socket create fail\n");
		return;
	}
	udpAttachRecv(iSockFd_recv,(FUNCPTR)OnSocket);

	printf("Create UDP RECV SOCKET DONE\n");
}

void udp_create_socket_send()
{
	struct in_addr addr;
	bzero((char *)&st_addrSend_send, sizeof(st_addrSend_send));
	bzero((char *)&addr, sizeof(addr));
	char buffer[100];

	sprintf (buffer, "%d.%d.%d.%d",g_ipAddr[0],g_ipAddr[1],g_ipAddr[2],g_ipAddr[3]);
	printf("IP:%s\n",buffer);
	iSockFd_send = socket(AF_INET, SOCK_DGRAM, 0);
	st_addrSend_send.sin_family = AF_INET;
	st_addrSend_send.sin_port = htons(UDP_SEND_DATA_PORT);
	st_addrSend_send.sin_addr.s_addr = inet_addr(UDP_SEND_GROUP);//UDP_SEND_IP
	addr.s_addr = inet_addr(buffer);//192.168.131.45
	setsockopt(iSockFd_send, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr, sizeof(addr));
	printf("Create UDP SEND SOCKET DONE\n");
}


int udp_send_data(int bytes)
{
	//printf("Come in udp_data_send...\n");
	sendto(iSockFd_send, (char *)send_buf, bytes, 0, (struct sockaddr *)&st_addrSend_send, sizeof(struct sockaddr_in));
	printf("udp send data Success length is %d\n",bytes);
	return 1;
}
